import { Enode } from "./Enode";

/*** 
 * 链表结构管理类。
 * 注：链表中的元素同时只能存在一个链表中 
 * 说明：链表中的元素需要实现Enode接口
 * (会自动添加Enode的__xxx属性
 */
export class Mnode{
    /** [readonly] 链表长度*/
    public size:number = 0;
    /** [readonly] 第一个元素*/
    public start:Enode;
    /** [readonly] 最后一个元素**/
    public end:Enode;

    public id:any=0;
    /** 用户数据 */
    public user:any;

    /** 重置列表，清空列表里的所有数据。**/
    public reset():void{
        var d:Mnode=this
        if(d.size>0){
            var n:Enode=d.start;
            var t:Enode=null;
            while (n!=null){
                t=n.__n;
                t.arr=null;
                t.__p=null;
                t.__n=null;
                t.reset();
                n=t;
            }
            d.start=null;
            d.end=null;
            d.size=0;
        }
    }
    /** 
     * 把当前列表的元素全部移动到新的列表末尾。
     * 注意：由于元素同一时间只能存在一个链表中，因此此方法处理结束后，当前列表元素将被清空。
     * @param to 目标链表
     */
    public move(to:Mnode):void{
        var d:Mnode=this;
        if(d.size>0){
            if(to.size==0){
                to.start=d.start;
                to.size=d.size;
            }else{
                to.size=to.size+d.size;
            }
            var t:Enode=d.start;
            t.__p=to.end;
            to.end=d.end;
            var n:Enode=t;
            while (n!=null){
                t=n.__n;
                n.arr=to;
                n=t;
            }
            d.start=null;
            d.end=null;
            d.size=0;
        }
    }
    /**
     * 将当前列表数据移到对象池中
     * @param p 
     */
    public free(p:Mnode):void{
        var f:Mnode=this;
        if(f.size>0&&f!=p){
            if(p.size==0){
                p.start=f.start;
                p.size=f.size;
            }else{
                p.size=p.size+f.size;
            }
            var t:Enode=f.start;
            t.__p=p.end;
            p.end=f.end;
            var n:Enode=t;
            while (n!=null){
                t=n.__n;
                n["reset"]();
                n.arr=p;
                n=t;
            }
            f.start=null;
            f.end=null;
            f.size=0;
        }
    }
    /** 对列表里的元素执行回调操作 */
    public forEach(cb:(item:any)=>void):void{
        var d:Mnode=this
        if(d.size>0){
            var n:Enode=d.start;
            var t:Enode=null;
            while (n!=null){
                t=n.__n;
                cb(n);
                n=t;
            }
        }
    }
    
    /**
     * 把指定元素插入到当前列表的首位
     * @param n
     * @return 
     */		
    public unshift(n:Enode):boolean{
        var d:Mnode=this;
        var e:Enode=d.start;
        if(n==e){
            return false;
        }
        d.remove(n);
        if(e!=null){
            n.__n=e;
            e.__p=n;
            d.start=n;
            d.size=d.size+1;
            n.arr=d
        }else{
            d.push(n);
        }
        return true;
    }

    /**
    * 添加一个节点在列表的末尾处。<p></p>
    * 注意：如果元素已经存在其他链表中，则会从其他列表中移除。如果已经在该链表中，则不作处理
    * @param d 要添加的列表
    * @param n 要操作的元素
    * @return 如果为当前列表末尾元素则返回false，否则会先从原来列表中移除（包含自身）添加到当前列表，返回true。
    */
    public push(n:Enode):boolean{
        var d:Mnode=this;
        if(n.arr==d){
            return false;
        }
        d.remove(n);
        d.size=d.size+1;
        if(d.start==null){
            d.start=n;
            //正常下这个值应该为null，无需设置。
            //n.prev=null;
        }else{
            d.end.__n=n;
            n.__p=d.end;
        }
        n.arr=d;
        //正常下这个值应该为null，无需设置。
        //n.next=null;
        d.end=n;
        return true;
    }
    /** 删除列表最后一个元素。**/
    public pop():Enode{
        var e:Enode=this.end;
        if(e!=null){
            this.remove2(e);
            return e;
        }
        return null;
    }
    /** 删除列表第一个元素**/
    public shift():Enode{
        var e:Enode=this.start;
        if(e!=null){
            this.remove2(e);
            return e;
        }
        return null;
    }
    /** 获取指定元素的下一个元素。 */
    public next(n:Enode):any{
        return n.__n;
    }
    /** 获取指定元素的上一个元素。 */
    public prev(n:Enode):any{
        return n.__p;
    }
    /**
    * 把节点从其列表中移除。（不论在哪个列表中都会移除）
    * @param n
    * @return 如果没有列表则返回false,反之为true
    */
    public remove(n:Enode):boolean{
        if(n.arr!=null){
            n.arr.remove2(n);
            return true;
        }
        return false;
    }
    /**
    * 从当前列表中移除。必须确保数据都正确。
    * @param n
    * @return 如果没有列表则返回false,反之为true
    */
   public remove2(n:Enode):void{
        var d:Mnode=this;
        d.size=d.size-1;
        
        var p:Enode=n.__p;
        var e:Enode=n.__n;
        if(p==null){
            d.start=e;
        }else{
            p.__n=e;
        }
        
        if(e==null){
            d.end=p;
        }else{
            e.__p=p;
        }
        n.arr=null;
        n.__p=null;
        n.__n=null;
    }
    /**
    * 获取指定元素在列表中的索引。(不论在哪个列表中)
    * @param n
    * @return 如果不存在列表中则返回-1。
    */
    public index(n:Enode):number{
        var d=this;
        if(n.arr!=d)return -1;
        var i:number=0;
        var t:Enode=n.__p;
        for(;t!=null;){
            i++;
            t=t.__p;
        }
        return i;
    }
    /**
    * 获取指定索引处的元素
    * @param index
    * @return 
    */
    public getAt(index:number):Enode{
        var d:Mnode=this;
        var c:number=d.size;
        if(index<0||index>=c) return null;
        var x:Enode;
        var i:number=0;
        if(index<(c*0.5)){//左边
            x=d.start;
            for(;i<index;i++){
                x=x.__n;
            }
        }
        else{//右边
            x=d.end;
            for(i=c-1;i>index;i--){
                x=x.__p;
            }
        }
        return x;
    }
    
}